package com.amarsoft.task;

import com.amarsoft.task.security.LoginModule;
import com.amarsoft.task.security.TaskUser;
import com.amarsoft.task.ui.TaskWindow;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

public class Task extends TaskObject
{
  private boolean parallelRun = false;
  @SuppressWarnings("unused")
  private boolean waitAllTargetsComplete = true;
  private Map<String, Target> targets = new LinkedHashMap<String, Target>();
  private ArrayList<TaskEventListener> listeners = null;
  private TaskWindow taskWindow = null;
  private LoginModule loginModule = null;
  private TaskUser taskUser = null;

  public Task()
  {
    this.listeners = new ArrayList<TaskEventListener>();
  }

  public final void start()
  {
    start(true);
  }

  public final void start(boolean waitAllComplete)
  {
    if ((this.taskUser == null) && (!(login()))) {
      this.logger.fatal("Must login to task first!");
      return;
    }
    fireTaskEvent(new TaskEvent(this, 0));
    this.waitAllTargetsComplete = waitAllComplete;
    trace(this);
    if (isParallelRun())
      runParallel();
    else
      runSerial();
    fireTaskEvent(new TaskEvent(this, 1));
  }

  public final void runTarget(String targetName, boolean newThread)
  {
    if ((this.taskUser == null) && (!(login()))) {
      this.logger.fatal("Must login to task first!");
      return;
    }
    Target target = getTarget(targetName);
    if (target != null) {
      trace(target);
      if (newThread)
        new Thread(target).start();
      else
        target.run();
    }
  }

  public final int executeUnit(String targetName, String unitName)
  {
    if ((this.taskUser == null) && (!(login()))) {
      this.logger.fatal("Must login to task first!");
      return 0;
    }
    Target target = getTarget(targetName);
    if (target != null) {
      trace(target);
      return target.executeUnit(unitName);
    }
    this.logger.error("Target <" + getName() + "." + targetName + "> not exists!");
    return 2; } 
  // ERROR //
  private void runParallel() { 
  }
    //   0: aconst_null
    //   1: astore_1
    //   2: aload_0
    //   3: invokevirtual 40	com/amarsoft/task/Task:getTargets	()[Lcom/amarsoft/task/Target;
    //   6: astore_2
    //   7: new 41	java/lang/ThreadGroup
    //   10: dup
    //   11: aload_0
    //   12: invokevirtual 35	com/amarsoft/task/Task:getName	()Ljava/lang/String;
    //   15: invokespecial 42	java/lang/ThreadGroup:<init>	(Ljava/lang/String;)V
    //   18: astore_3
    //   19: iconst_0
    //   20: istore 4
    //   22: iload 4
    //   24: aload_2
    //   25: arraylength
    //   26: if_icmpge +45 -> 71
    //   29: aload_2
    //   30: iload 4
    //   32: aaload
    //   33: astore_1
    //   34: aload_1
    //   35: invokevirtual 43	com/amarsoft/task/Target:isEnabled	()Z
    //   38: ifne +6 -> 44
    //   41: goto +24 -> 65
    //   44: aload_0
    //   45: aload_1
    //   46: invokevirtual 21	com/amarsoft/task/Task:trace	(Lcom/amarsoft/task/TaskObject;)V
    //   49: new 26	java/lang/Thread
    //   52: dup
    //   53: aload_3
    //   54: aload_1
    //   55: aload_1
    //   56: invokevirtual 44	com/amarsoft/task/Target:getName	()Ljava/lang/String;
    //   59: invokespecial 45	java/lang/Thread:<init>	(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;Ljava/lang/String;)V
    //   62: invokevirtual 28	java/lang/Thread:start	()V
    //   65: iinc 4 1
    //   68: goto -46 -> 22
    //   71: aload_0
    //   72: getfield 3	com/amarsoft/task/Task:waitAllTargetsComplete	Z
    //   75: ifeq +27 -> 102
    //   78: aload_3
    //   79: invokevirtual 46	java/lang/ThreadGroup:activeCount	()I
    //   82: ifne +6 -> 88
    //   85: goto +17 -> 102
    //   88: ldc2_w 47
    //   91: invokestatic 49	java/lang/Thread:sleep	(J)V
    //   94: goto -23 -> 71
    //   97: astore 4
    //   99: goto -28 -> 71
    //   102: return
    //
    // Exception table:
    //   from	to	target	type
    //   88	94	97	java/lang/InterruptedException } 
  private void runSerial() { Target target = null;
    Target[] allTarget = getTargets();
    for (int i = 0; i < allTarget.length; ++i) {
      target = allTarget[i];
      if (target.isEnabled()) {
        trace(target);
        target.run();
      }
    }
  }

  public final boolean isParallelRun()
  {
    return this.parallelRun;
  }

  public final void setParallelRun(boolean parallelRun)
  {
    this.parallelRun = parallelRun;
  }

  public final void addTarget(Target target)
  {
    target.setTask(this);
    this.targets.put(target.getName(), target);
    fireTaskEvent(6, target, null, null);
  }

  public final void removeTarget(String name)
  {
    if (this.targets.containsKey(name)) {
      Target t = this.targets.get(name);
      this.targets.remove(name);
      fireTaskEvent(7, t, null, null);
    }
  }

  public final void removeTarget(Target target)
  {
    if ((target != null) && (this.targets.containsKey(target.getName()))) {
      this.targets.remove(target.getName());
      fireTaskEvent(7, target, null, null);
    }
  }

  public final Target getTarget(String name)
  {
    return this.targets.get(name);
  }

  public final Target[] getTargets()
  {
    Target[] t = new Target[this.targets.size()];
    return this.targets.values().toArray(t);
  }

  public final int getTargetCount()
  {
    return this.targets.size();
  }

  protected void fireTaskEvent(int eventType, Target relativeTarget, ExecuteUnit relativeUnit, Route relativeRoute)
  {
    TaskEvent e = new TaskEvent(this, eventType, relativeTarget, relativeUnit, relativeRoute);
    fireTaskEvent(e);
  }

  protected void fireTaskEvent(TaskEvent e)
  {
    for (int i = 0; i < this.listeners.size(); ++i) {
      TaskEventListener l = this.listeners.get(i);
      switch (e.getType())
      {
      case 0:
        l.taskStart(e);
        break;
      case 1:
        l.taskExit(e);
        break;
      case 2:
        l.targetStart(e);
        break;
      case 3:
        l.targetExit(e);
        break;
      case 4:
        l.unitStart(e);
        break;
      case 5:
        l.unitExit(e);
        break;
      case 6:
        l.targetAdded(e);
        break;
      case 7:
        l.targetRemoved(e);
        break;
      case 8:
        l.unitAdded(e);
        break;
      case 9:
        l.unitRemoved(e);
        break;
      case 10:
        l.routeAdded(e);
        break;
      case 11:
        l.routeRemoved(e);
      }
    }
  }

  public void addTaskEventListener(TaskEventListener l)
  {
    if (!(this.listeners.contains(l)))
      this.listeners.add(l);
  }

  public void removeTaskEventListener(TaskEventListener l)
  {
    if (this.listeners.contains(l))
      this.listeners.remove(l);
  }

  protected TaskUser getTaskUser()
  {
    return this.taskUser;
  }

  protected boolean login()
  {
    this.taskUser = this.loginModule.login(this);
    return (this.taskUser != null);
  }

  public LoginModule getLoginModule()
  {
    return this.loginModule;
  }

  public void setLoginModule(LoginModule loginModule)
  {
    this.loginModule = loginModule;
  }

  public TaskWindow getTaskWindow()
  {
    return this.taskWindow;
  }

  public void setTaskWindow(TaskWindow taskWindow)
  {
    this.taskWindow = taskWindow;
  }
}